/* Copyright 2009
 *
 * This program and the accompanying materials
 * are made available under the terms of the
 * Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at
 *
 * 		http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
 * OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * Contributors:
 * 	   IBM Corporation - initial API and implementation for JDT/DLTK
 *     Sean W. Quinn - initial adoption for use with PHP from various sources.
 */
package org.eclipse.php.core;

import java.util.Map;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.dltk.core.IBuildpathContainer;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IField;
import org.eclipse.dltk.core.IMethod;
import org.eclipse.dltk.core.IOpenable;
import org.eclipse.dltk.core.IParent;
import org.eclipse.dltk.core.IRegion;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ITypeHierarchy;
import org.eclipse.dltk.core.WorkingCopyOwner;
import org.eclipse.php.core.eval.IEvaluationContext;
import org.eclipse.php.internal.core.ast.nodes.IMethodBinding;
import org.eclipse.php.internal.core.ast.nodes.INamespaceBinding;
import org.eclipse.php.internal.core.ast.nodes.ITypeBinding;
import org.eclipse.php.internal.core.ast.nodes.IVariableBinding;

/**
 * A PHP project represents a view of a project resource in terms of PHP
 * elements such as package fragments, types, methods and fields. A project may
 * contain several package roots, which contain package fragments. A package
 * root corresponds to an underlying folder or JAR.
 * <p>
 * Each PHP project has a classpath, defining which folders contain source code
 * and where required libraries are located. Each PHP project also has an output
 * location, defining where the builder writes <code>.class</code> files. A
 * project that references packages in another project can access the packages
 * by including the required project in a classpath entry. The PHP model will
 * present the source elements in the required project; when building, the
 * compiler will use the corresponding generated class files from the required
 * project's output location(s)). The classpath format is a sequence of
 * classpath entries describing the location and contents of package fragment
 * roots.
 * </p>
 * PHP project elements need to be opened before they can be navigated or
 * manipulated. The children of a PHP project are the package fragment roots
 * that are defined by the classpath and contained in this project (in other
 * words, it does not include package fragment roots for other projects). </p>
 * <p>
 * An instance of one of these handles can be created via
 * <code>PHPCore.create(project)</code>.
 * </p>
 *
 * @see PHPCore#create(org.eclipse.core.resources.IProject)
 * @see IBuildpathEntry
 * @noimplement This interface is not intended to be implemented by clients.
 */
public interface IPHPProject extends IParent, IPHPElement, IOpenable, IScriptProject {

	/**
	 * Decodes the classpath entry that has been encoded in the given string in
	 * the context of this project. Returns null if the encoded entry is
	 * malformed.
	 *
	 * @param encodedEntry the encoded classpath entry
	 * @return the decoded classpath entry, or <code>null</code> if unable to
	 *         decode it
	 * @since 3.2
	 */
	IBuildpathEntry decodeClasspathEntry(String encodedEntry);

	/**
	 * Encodes the given classpath entry into a string in the context of this
	 * project.
	 *
	 * @param classpathEntry the classpath entry to encode
	 * @return the encoded classpath entry
	 * @since 3.2
	 */
	String encodeClasspathEntry(IBuildpathEntry classpathEntry);

	/**
	 * Returns the <code>IPHPElement</code> corresponding to the given
	 * classpath-relative path, or <code>null</code> if no such
	 * <code>IPHPElement</code> is found. The result is one of an
	 * <code>IProgramUnit</code>, <code>IClassFile</code>, or
	 * <code>INamespaceFragment</code>.
	 * <p>
	 * When looking for a package fragment, there might be several potential
	 * matches; only one of them is returned.
	 * <p>
	 * For example, the path "java/lang/Object.java", would result in the
	 * <code>IProgramUnit</code> or <code>IClassFile</code> corresponding to
	 * "java.lang.Object". The path "java/lang" would result in the
	 * <code>INamespaceFragment</code> for "java.lang".
	 *
	 * @param path the given classpath-relative path
	 * @exception PHPModelException if the given path is <code>null</code> or
	 *                absolute
	 * @return the <code>IPHPElement</code> corresponding to the given
	 *         classpath-relative path, or <code>null</code> if no such
	 *         <code>IPHPElement</code> is found
	 */
	IPHPElement findElement(IPath path) throws PHPModelException;

	/**
	 * Returns the <code>IPHPElement</code> corresponding to the given
	 * classpath-relative path, or <code>null</code> if no such
	 * <code>IPHPElement</code> is found. The result is one of an
	 * <code>IProgramUnit</code>, <code>IClassFile</code>, or
	 * <code>INamespaceFragment</code>. If it is an
	 * <code>IProgramUnit</code>, its owner is the given owner.
	 * <p>
	 * When looking for a package fragment, there might be several potential
	 * matches; only one of them is returned.
	 * <p>
	 * For example, the path "java/lang/Object.java", would result in the
	 * <code>IProgramUnit</code> or <code>IClassFile</code> corresponding to
	 * "java.lang.Object". The path "java/lang" would result in the
	 * <code>INamespaceFragment</code> for "java.lang".
	 *
	 * @param path the given classpath-relative path
	 * @param owner the owner of the returned compilation unit, ignored if it is
	 *            not a compilation unit.
	 * @exception PHPModelException if the given path is <code>null</code> or
	 *                absolute
	 * @return the <code>IPHPElement</code> corresponding to the given
	 *         classpath-relative path, or <code>null</code> if no such
	 *         <code>IPHPElement</code> is found
	 * @since 3.0
	 */
	IPHPElement findElement(IPath path, WorkingCopyOwner owner) throws PHPModelException;

	/**
	 * Finds the PHP element corresponding to the given binding key if any, else
	 * returns <code>null</code>. Elements are looked up using this project's
	 * classpath. The first element corresponding to the given key on this
	 * project's classpath is returned.
	 * <p>
	 * Possible elements are:
	 * <ul>
	 * <li>{@link INamespaceFragment} for a binding key from an
	 * {@link INamespaceBinding}</li>
	 * <li>{@link IType} for a binding key from an {@link ITypeBinding}</li>
	 * <li>{@link IMethod} for a binding key from an {@link IMethodBinding}</li>
	 * <li>{@link IField} for a binding key from an {@link IVariableBinding}
	 * representing a {@link IVariableBinding#isField() field}</li>
	 * </ul>
	 * </p>
	 * <p>
	 * Note: if two methods correspond to the binding key because their
	 * parameter types' simple names are the same, then the first one is
	 * returned. For example, if a class defines two methods
	 * <code>foo(p1.Y, String)</code> and <code>foo(p2.Y, String)</code>, in
	 * both cases the parameter type's simple names are
	 * <code>{"Y", "String"}</code>. Thus <code>foo(p1.Y, String)</code> is
	 * returned.
	 * </p>
	 *
	 * @param bindingKey the given binding key
	 * @param owner the owner of the returned element's compilation unit, or
	 *            <code>null</code> if the default working copy owner must be
	 *            used
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the PHP element corresponding to the given key, or
	 *         <code>null</code> if no such PHP element is found
	 * @since 3.4
	 */
	IPHPElement findElement(String bindingKey, WorkingCopyOwner owner) throws PHPModelException;

	/**
	 * Returns the first existing package fragment on this project's classpath
	 * whose path matches the given (absolute) path, or <code>null</code> if
	 * none exist. The path can be: - internal to the workbench: "/Project/src"
	 * - external to the workbench: "c:/jdk/classes.zip/java/lang"
	 *
	 * @param path the given absolute path
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first existing package fragment on this project's classpath
	 *         whose path matches the given (absolute) path, or
	 *         <code>null</code> if none exist
	 */
	INamespaceFragment findNamespaceFragment(IPath path) throws PHPModelException;

	/**
	 * Returns the existing package fragment root on this project's classpath
	 * whose path matches the given (absolute) path, or <code>null</code> if one
	 * does not exist. The path can be: - internal to the workbench:
	 * "/Compiler/src" - external to the workbench: "c:/jdk/classes.zip"
	 *
	 * @param path the given absolute path
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the existing package fragment root on this project's classpath
	 *         whose path matches the given (absolute) path, or
	 *         <code>null</code> if one does not exist
	 */
	INamespaceFragmentRoot findNamespaceFragmentRoot(IPath path) throws PHPModelException;

	/**
	 * Returns the existing package fragment roots identified by the given
	 * entry. Note that a classpath entry that refers to another project may
	 * have more than one root (if that project has more than on root containing
	 * source), and classpath entries within the current project identify a
	 * single root.
	 * <p>
	 * If the classpath entry denotes a variable, it will be resolved and return
	 * the roots of the target entry (empty if not resolvable).
	 * <p>
	 * If the classpath entry denotes a container, it will be resolved and
	 * return the roots corresponding to the set of container entries (empty if
	 * not resolvable).
	 *
	 * @param entry the given entry
	 * @return the existing package fragment roots identified by the given entry
	 * @see IBuildpathContainer
	 * @since 2.1
	 */
	INamespaceFragmentRoot[] findNamespaceFragmentRoots(IBuildpathEntry entry);

	/**
	 * Returns the first type found following this project's classpath with the
	 * given fully qualified name or <code>null</code> if none is found. The
	 * fully qualified name is a dot-separated name. For example, a class B
	 * defined as a member type of a class A in package x.y should have a the
	 * fully qualified name "x.y.A.B". Note that in order to be found, a type
	 * name (or its toplevel enclosing type name) must match its corresponding
	 * compilation unit name. As a consequence, secondary types cannot be found
	 * using this functionality. To find secondary types use
	 * {@link #findType(String, IProgressMonitor)} instead.
	 *
	 * @param fullyQualifiedName the given fully qualified name
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given fully qualified name or <code>null</code> if none is found
	 * @see IType#getFullyQualifiedName(char)
	 * @since 2.0
	 */
	IType findType(String fullyQualifiedName) throws PHPModelException;

	/**
	 * Same functionality as {@link #findType(String)} but also look for
	 * secondary types if given name does not match a compilation unit name.
	 *
	 * @param fullyQualifiedName the given fully qualified name
	 * @param progressMonitor the progress monitor to report progress to, or
	 *            <code>null</code> if no progress monitor is provided
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given fully qualified name or <code>null</code> if none is found
	 * @see IType#getFullyQualifiedName(char)
	 * @since 3.2
	 */
	IType findType(String fullyQualifiedName, IProgressMonitor progressMonitor) throws PHPModelException;

	/**
	 * Returns the first type found following this project's classpath with the
	 * given fully qualified name or <code>null</code> if none is found. The
	 * fully qualified name is a dot-separated name. For example, a class B
	 * defined as a member type of a class A in package x.y should have a the
	 * fully qualified name "x.y.A.B". If the returned type is part of a
	 * compilation unit, its owner is the given owner. Note that in order to be
	 * found, a type name (or its toplevel enclosing type name) must match its
	 * corresponding compilation unit name. As a consequence, secondary types
	 * cannot be found using this functionality. To find secondary types use
	 * {@link #findType(String, WorkingCopyOwner, IProgressMonitor)} instead.
	 *
	 * @param fullyQualifiedName the given fully qualified name
	 * @param owner the owner of the returned type's compilation unit
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given fully qualified name or <code>null</code> if none is found
	 * @see IType#getFullyQualifiedName(char)
	 * @since 3.0
	 */
	IType findType(String fullyQualifiedName, WorkingCopyOwner owner) throws PHPModelException;

	/**
	 * Same functionality as {@link #findType(String, WorkingCopyOwner)} but
	 * also look for secondary types if given name does not match a compilation
	 * unit name.
	 *
	 * @param fullyQualifiedName the given fully qualified name
	 * @param owner the owner of the returned type's compilation unit
	 * @param progressMonitor the progress monitor to report progress to, or
	 *            <code>null</code> if no progress monitor is provided
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given fully qualified name or <code>null</code> if none is found
	 * @see IType#getFullyQualifiedName(char)
	 * @since 3.2
	 */
	IType findType(String fullyQualifiedName, WorkingCopyOwner owner, IProgressMonitor progressMonitor)
			throws PHPModelException;

	/**
	 * Returns the first type found following this project's classpath with the
	 * given package name and type qualified name or <code>null</code> if none
	 * is found. The package name is a dot-separated name. The type qualified
	 * name is also a dot-separated name. For example, a class B defined as a
	 * member type of a class A should have the type qualified name "A.B". Note
	 * that in order to be found, a type name (or its toplevel enclosing type
	 * name) must match its corresponding compilation unit name. As a
	 * consequence, secondary types cannot be found using this functionality. To
	 * find secondary types use
	 * {@link #findType(String, String, IProgressMonitor)} instead.
	 *
	 * @param packageName the given package name
	 * @param typeQualifiedName the given type qualified name
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given package name and type qualified name or <code>null</code>
	 *         if none is found
	 * @see IType#getTypeQualifiedName(char)
	 * @since 2.0
	 */
	IType findType(String packageName, String typeQualifiedName) throws PHPModelException;

	/**
	 * Same functionality as {@link #findType(String, String)} but also look for
	 * secondary types if given name does not match a compilation unit name.
	 *
	 * @param packageName the given package name
	 * @param typeQualifiedName the given type qualified name
	 * @param progressMonitor the progress monitor to report progress to, or
	 *            <code>null</code> if no progress monitor is provided
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given fully qualified name or <code>null</code> if none is found
	 * @see IType#getFullyQualifiedName(char)
	 * @since 3.2
	 */
	IType findType(String packageName, String typeQualifiedName, IProgressMonitor progressMonitor)
			throws PHPModelException;

	/**
	 * Returns the first type found following this project's classpath with the
	 * given package name and type qualified name or <code>null</code> if none
	 * is found. The package name is a dot-separated name. The type qualified
	 * name is also a dot-separated name. For example, a class B defined as a
	 * member type of a class A should have the type qualified name "A.B". If
	 * the returned type is part of a compilation unit, its owner is the given
	 * owner. Note that in order to be found, a type name (or its toplevel
	 * enclosing type name) must match its corresponding compilation unit name.
	 * As a consequence, secondary types cannot be found using this
	 * functionality. To find secondary types use
	 * {@link #findType(String, String, WorkingCopyOwner, IProgressMonitor)}
	 * instead.
	 *
	 * @param packageName the given package name
	 * @param typeQualifiedName the given type qualified name
	 * @param owner the owner of the returned type's compilation unit
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given package name and type qualified name or <code>null</code>
	 *         if none is found
	 * @see IType#getTypeQualifiedName(char)
	 * @since 3.0
	 */
	IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner) throws PHPModelException;

	/**
	 * Same functionality as {@link #findType(String, String, WorkingCopyOwner)}
	 * but also look for secondary types if given name does not match a
	 * compilation unit name.
	 *
	 * @param packageName the given package name
	 * @param typeQualifiedName the given type qualified name
	 * @param owner the owner of the returned type's compilation unit
	 * @param progressMonitor the progress monitor to report progress to, or
	 *            <code>null</code> if no progress monitor is provided
	 * @exception PHPModelException if this project does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @return the first type found following this project's classpath with the
	 *         given fully qualified name or <code>null</code> if none is found
	 * @see IType#getFullyQualifiedName(char)
	 * @since 3.2
	 */
	IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner,
			IProgressMonitor progressMonitor) throws PHPModelException;

	/**
	 * Returns all of the existing package fragment roots that exist on the
	 * classpath, in the order they are defined by the classpath.
	 *
	 * @return all of the existing package fragment roots that exist on the
	 *         classpath
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 */
	INamespaceFragmentRoot[] getAllNamespaceFragmentRoots() throws PHPModelException;

	/**
	 * Returns an array of non-PHP resources directly contained in this project.
	 * It does not transitively answer non-PHP resources contained in folders;
	 * these would have to be explicitly iterated over.
	 * <p>
	 * Non-PHP resources includes other files and folders located in the project
	 * not accounted for by any of it source or binary package fragment roots.
	 * If the project is a source folder itself, resources excluded from the
	 * corresponding source classpath entry by one or more exclusion patterns
	 * are considered non-PHP resources and will appear in the result (possibly
	 * in a folder)
	 * </p>
	 *
	 * @return an array of non-PHP resources (<code>IFile</code>s and/or
	 *         <code>IFolder</code>s) directly contained in this project
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 */
	Object[] getNonPHPResources() throws PHPModelException;

	/**
	 * Helper method for returning one option value only. Equivalent to
	 * <code>(String)this.getOptions(inheritPHPCoreOptions).get(optionName)</code>
	 * Note that it may answer <code>null</code> if this option does not exist,
	 * or if there is no custom value for it.
	 * <p>
	 * For a complete description of the configurable options, see
	 * <code>PHPCore#getDefaultOptions</code>.
	 * </p>
	 *
	 * @param optionName the name of an option
	 * @param inheritPHPCoreOptions - boolean indicating whether PHPCore options
	 *            should be inherited as well
	 * @return the String value of a given option
	 * @see PHPCore#getDefaultOptions()
	 * @since 2.1
	 */
	String getOption(String optionName, boolean inheritPHPCoreOptions);

	/**
	 * Returns the table of the current custom options for this project.
	 * Projects remember their custom options, in other words, only the options
	 * different from the the PHPCore global options for the workspace. A
	 * boolean argument allows to directly merge the project options with global
	 * ones from <code>PHPCore</code>.
	 * <p>
	 * For a complete description of the configurable options, see
	 * <code>PHPCore#getDefaultOptions</code>.
	 * </p>
	 *
	 * @param inheritPHPCoreOptions - boolean indicating whether PHPCore options
	 *            should be inherited as well
	 * @return table of current settings of all options (key type:
	 *         <code>String</code>; value type: <code>String</code>)
	 * @see PHPCore#getDefaultOptions()
	 * @since 2.1
	 */
	Map getOptions(boolean inheritPHPCoreOptions);

	/**
	 * Returns the default output location for this project as a workspace-
	 * relative absolute path.
	 * <p>
	 * The default output location is where class files are ordinarily generated
	 * (and resource files, copied). Each source classpath entry can also
	 * specify an output location for the generated class files (and copied
	 * resource files) corresponding to compilation units under that source
	 * folder. This makes it possible to arrange generated class files for
	 * different source folders in different output folders, and not necessarily
	 * the default output folder. This means that the generated class files for
	 * the project may end up scattered across several folders, rather than all
	 * in the default output folder (which is more standard).
	 * </p>
	 *
	 * @return the workspace-relative absolute path of the default output folder
	 * @exception PHPModelException if this element does not exist
	 * @see #setOutputLocation(org.eclipse.core.runtime.IPath, IProgressMonitor)
	 * @see IBuildpathEntry#getOutputLocation()
	 */
	IPath getOutputLocation() throws PHPModelException;

	/**
	 * Returns a package fragment root for an external library (a ZIP archive -
	 * e.g. a <code>.jar</code>, a <code>.zip</code> file, etc. - or - since 3.4
	 * - a class folder) at the specified file system path. This is a
	 * handle-only method. The underlying <code>java.io.File</code> may or may
	 * not exist. No resource is associated with this local library package
	 * fragment root.
	 *
	 * @param externalLibraryPath the library's file system path
	 * @return a package fragment root for the external library at the specified
	 *         file system path
	 */
	INamespaceFragmentRoot getNamespaceFragmentRoot(String externalLibraryPath);

	/**
	 * Returns a package fragment root for the given resource, which must either
	 * be a folder representing the top of a package hierarchy, or a ZIP archive
	 * (e.g. a <code>.jar</code>, a <code>.zip</code> file, etc.) This is a
	 * handle-only method. The underlying resource may or may not exist.
	 *
	 * @param resource the given resource
	 * @return a package fragment root for the given resource, which must either
	 *         be a folder representing the top of a package hierarchy, or a ZIP
	 *         archive (e.g. a <code>.jar</code>, a <code>.zip</code> file,
	 *         etc.)
	 */
	INamespaceFragmentRoot getNamespaceFragmentRoot(IResource resource);

	/**
	 * Returns all of the package fragment roots contained in this project,
	 * identified on this project's resolved classpath. The result does not
	 * include package fragment roots in other projects referenced on this
	 * project's classpath.
	 * <p>
	 * NOTE: This is equivalent to <code>getChildren()</code>.
	 *
	 * @return all of the package fragment roots contained in this project,
	 *         identified on this project's resolved classpath
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 */
	INamespaceFragmentRoot[] getNamespaceFragmentRoots() throws PHPModelException;

	/**
	 * Returns all package fragments in all package fragment roots contained in
	 * this project. This is a convenience method. Note that the package
	 * fragment roots corresponds to the resolved classpath of the project.
	 *
	 * @return all package fragments in all package fragment roots contained in
	 *         this project
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 */
	INamespaceFragment[] getNamespaceFragments() throws PHPModelException;

	/**
	 * Returns the <code>IProject</code> on which this <code>IPHPProject</code>
	 * was created. This is handle-only method.
	 *
	 * @return the <code>IProject</code> on which this <code>IPHPProject</code>
	 *         was created
	 */
	IProject getProject();

	/**
	 * Returns the raw classpath for the project, as a list of classpath
	 * entries. This corresponds to the exact set of entries which were assigned
	 * using <code>setRawClasspath</code>, in particular such a classpath may
	 * contain classpath variable and classpath container entries. Classpath
	 * variable and classpath container entries can be resolved using the helper
	 * method <code>getResolvedClasspath</code>; classpath variable entries also
	 * can be resolved individually using
	 * <code>PHPCore#getClasspathVariable</code>).
	 * <p>
	 * Both classpath containers and classpath variables provides a level of
	 * indirection that can make the <code>.classpath</code> file stable across
	 * workspaces. As an example, classpath variables allow a classpath to no
	 * longer refer directly to external JARs located in some user specific
	 * location. The classpath can simply refer to some variables defining the
	 * proper locations of these external JARs. Similarly, classpath containers
	 * allows classpath entries to be computed dynamically by the plug-in that
	 * defines that kind of classpath container.
	 * </p>
	 * <p>
	 * Note that in case the project isn't yet opened, the classpath will be
	 * read directly from the associated <tt>.classpath</tt> file.
	 * </p>
	 *
	 * @return the raw classpath for the project, as a list of classpath entries
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @see IBuildpathEntry
	 */
	IBuildpathEntry[] getRawClasspath() throws PHPModelException;

	/**
	 * Returns the names of the projects that are directly required by this
	 * project. A project is required if it is in its classpath.
	 * <p>
	 * The project names are returned in the order they appear on the classpath.
	 *
	 * @return the names of the projects that are directly required by this
	 *         project in classpath order
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 */
	String[] getRequiredProjectNames() throws PHPModelException;

	/**
	 * This is a helper method returning the resolved classpath for the project
	 * as a list of simple (non-variable, non-container) classpath entries. All
	 * classpath variable and classpath container entries in the project's raw
	 * classpath will be replaced by the simple classpath entries they resolve
	 * to.
	 * <p>
	 * The resulting resolved classpath is accurate for the given point in time.
	 * If the project's raw classpath is later modified, or if classpath
	 * variables are changed, the resolved classpath can become out of date.
	 * Because of this, hanging on resolved classpath is not recommended.
	 * </p>
	 * <p>
	 * Note that if the resolution creates duplicate entries (i.e.
	 * {@link IBuildpathEntry entries} which are {@link Object#equals(Object)}),
	 * only the first one is added to the resolved classpath.
	 * </p>
	 *
	 * @param ignoreUnresolvedEntry indicates how to handle unresolvable
	 *            variables and containers; <code>true</code> indicates that
	 *            missing variables and unresolvable classpath containers should
	 *            be silently ignored, and that the resulting list should
	 *            consist only of the entries that could be successfully
	 *            resolved; <code>false</code> indicates that a
	 *            <code>PHPModelException</code> should be thrown for the first
	 *            unresolved variable or container
	 * @return the resolved classpath for the project as a list of simple
	 *         classpath entries, where all classpath variable and container
	 *         entries have been resolved and substituted with their final
	 *         target entries
	 * @exception PHPModelException in one of the corresponding situation:
	 *                <ul>
	 *                <li>this element does not exist</li>
	 *                <li>an exception occurs while accessing its corresponding
	 *                resource</li>
	 *                <li>a classpath variable or classpath container was not
	 *                resolvable and <code>ignoreUnresolvedEntry</code> is
	 *                <code>false</code>.</li>
	 *                </ul>
	 * @see IBuildpathEntry
	 */
	IBuildpathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry) throws PHPModelException;

	/**
	 * Returns whether this project has been built at least once and thus
	 * whether it has a build state.
	 *
	 * @return true if this project has been built at least once, false
	 *         otherwise
	 */
	boolean hasBuildState();

	/**
	 * Returns whether setting this project's classpath to the given classpath
	 * entries would result in a cycle. If the set of entries contains some
	 * variables, those are resolved in order to determine cycles.
	 *
	 * @param entries the given classpath entries
	 * @return true if the given classpath entries would result in a cycle,
	 *         false otherwise
	 */
	boolean hasClasspathCycle(IBuildpathEntry[] entries);

	/**
	 * Returns whether the given element is on the classpath of this project,
	 * that is, referenced from a classpath entry and not explicitly excluded
	 * using an exclusion pattern.
	 *
	 * @param element the given element
	 * @return <code>true</code> if the given element is on the classpath of
	 *         this project, <code>false</code> otherwise
	 * @see IBuildpathEntry#getInclusionPatterns()
	 * @see IBuildpathEntry#getExclusionPatterns()
	 * @since 2.0
	 */
	boolean isOnClasspath(IPHPElement element);

	/**
	 * Returns whether the given resource is on the classpath of this project,
	 * that is, referenced from a classpath entry and not explicitly excluded
	 * using an exclusion pattern.
	 *
	 * @param resource the given resource
	 * @return <code>true</code> if the given resource is on the classpath of
	 *         this project, <code>false</code> otherwise
	 * @see IBuildpathEntry#getInclusionPatterns()
	 * @see IBuildpathEntry#getExclusionPatterns()
	 * @since 2.1
	 */
	boolean isOnClasspath(IResource resource);

	/**
	 * Creates a new evaluation context.
	 *
	 * @return a new evaluation context.
	 */
	IEvaluationContext newEvaluationContext();

	/**
	 * Creates and returns a type hierarchy for all types in the given region,
	 * considering subtypes within that region.
	 *
	 * @param monitor the given progress monitor
	 * @param region the given region
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @exception IllegalArgumentException if region is <code>null</code>
	 * @return a type hierarchy for all types in the given region, considering
	 *         subtypes within that region
	 */
	ITypeHierarchy newTypeHierarchy(IRegion region, IProgressMonitor monitor) throws PHPModelException;

	/**
	 * Creates and returns a type hierarchy for all types in the given region,
	 * considering subtypes within that region and considering types in the
	 * working copies with the given owner. In other words, the owner's working
	 * copies will take precedence over their original compilation units in the
	 * workspace.
	 * <p>
	 * Note that if a working copy is empty, it will be as if the original
	 * compilation unit had been deleted.
	 * <p>
	 *
	 * @param monitor the given progress monitor
	 * @param region the given region
	 * @param owner the owner of working copies that take precedence over their
	 *            original compilation units
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @exception IllegalArgumentException if region is <code>null</code>
	 * @return a type hierarchy for all types in the given region, considering
	 *         subtypes within that region
	 * @since 3.0
	 */
	ITypeHierarchy newTypeHierarchy(IRegion region, WorkingCopyOwner owner, IProgressMonitor monitor)
			throws PHPModelException;

	/**
	 * Creates and returns a type hierarchy for the given type considering
	 * subtypes in the specified region.
	 *
	 * @param type the given type
	 * @param region the given region
	 * @param monitor the given monitor
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @exception IllegalArgumentException if type or region is
	 *                <code>null</code>
	 * @return a type hierarchy for the given type considering subtypes in the
	 *         specified region
	 */
	ITypeHierarchy newTypeHierarchy(IType type, IRegion region, IProgressMonitor monitor) throws PHPModelException;

	/**
	 * Creates and returns a type hierarchy for the given type considering
	 * subtypes in the specified region and considering types in the working
	 * copies with the given owner. In other words, the owner's working copies
	 * will take precedence over their original compilation units in the
	 * workspace.
	 * <p>
	 * Note that if a working copy is empty, it will be as if the original
	 * compilation unit had been deleted.
	 * <p>
	 *
	 * @param type the given type
	 * @param region the given region
	 * @param monitor the given monitor
	 * @param owner the owner of working copies that take precedence over their
	 *            original compilation units
	 * @exception PHPModelException if this element does not exist or if an
	 *                exception occurs while accessing its corresponding
	 *                resource
	 * @exception IllegalArgumentException if type or region is
	 *                <code>null</code>
	 * @return a type hierarchy for the given type considering subtypes in the
	 *         specified region
	 * @since 3.0
	 */
	ITypeHierarchy newTypeHierarchy(IType type, IRegion region, WorkingCopyOwner owner, IProgressMonitor monitor)
			throws PHPModelException;

	/**
	 * Returns the default output location for the project as defined by its
	 * <code>.classpath</code> file from disk, or <code>null</code> if unable to
	 * read the file.
	 * <p>
	 * This output location may differ from the in-memory one returned by
	 * <code>getOutputLocation</code>, in case the automatic reconciliation
	 * mechanism has not been performed yet. Usually, any change to the
	 * <code>.classpath</code> file is automatically noticed and reconciled at
	 * the next resource change notification event. However, if the file is
	 * modified within an operation, where this change needs to be taken into
	 * account before the operation ends, then the output location from disk can
	 * be read using this method, and further assigned to the project using
	 * <code>setRawClasspath(...)</code>.
	 * <p>
	 * The default output location is where class files are ordinarily generated
	 * (and resource files, copied). Each source classpath entry can also
	 * specify an output location for the generated class files (and copied
	 * resource files) corresponding to compilation units under that source
	 * folder. This makes it possible to arrange generated class files for
	 * different source folders in different output folders, and not necessarily
	 * the default output folder. This means that the generated class files for
	 * the project may end up scattered across several folders, rather than all
	 * in the default output folder (which is more standard).
	 * <p>
	 * In order to manually force a project classpath refresh, one can simply
	 * assign the project classpath using the result of this method, as follows:
	 *
	 * <code>proj.setRawClasspath(proj.readRawClasspath(), proj.readOutputLocation(), monitor)</code>
	 * (note that the <code>readRawClasspath/readOutputLocation</code> methods
	 * could return <code>null</code>).
	 * <p>
	 *
	 * @return the workspace-relative absolute path of the default output folder
	 * @see #getOutputLocation()
	 * @since 3.0
	 */
	IPath readOutputLocation();

	/**
	 * Returns the raw classpath for the project as defined by its
	 * <code>.classpath</code> file from disk, or <code>null</code> if unable to
	 * read the file.
	 * <p>
	 * This classpath may differ from the in-memory classpath returned by
	 * <code>getRawClasspath</code>, in case the automatic reconciliation
	 * mechanism has not been performed yet. Usually, any change to the
	 * <code>.classpath</code> file is automatically noticed and reconciled at
	 * the next resource change notification event. However, if the file is
	 * modified within an operation, where this change needs to be taken into
	 * account before the operation ends, then the classpath from disk can be
	 * read using this method, and further assigned to the project using
	 * <code>setRawClasspath(...)</code>.
	 * </p>
	 * <p>
	 * Classpath variable and classpath container entries can be resolved using
	 * the helper method <code>getResolvedClasspath</code>; classpath variable
	 * entries also can be resolved individually using
	 * <code>PHPCore#getClasspathVariable</code>).
	 * </p>
	 * <p>
	 * Note that no check is performed whether the project has the PHP nature
	 * set, allowing an existing <code>.classpath</code> file to be considered
	 * independantly (unlike <code>getRawClasspath</code> which requires the PHP
	 * nature to be associated with the project).
	 * </p>
	 * <p>
	 * In order to manually force a project classpath refresh, one can simply
	 * assign the project classpath using the result of this method, as follows:
	 *
	 * <code>proj.setRawClasspath(proj.readRawClasspath(), proj.readOutputLocation(), monitor)</code>
	 * (note that the <code>readRawClasspath/readOutputLocation</code> methods
	 * could return <code>null</code>).
	 * </p>
	 *
	 * @return the raw classpath from disk for the project, as a list of
	 *         classpath entries
	 * @see #getRawClasspath()
	 * @see IBuildpathEntry
	 * @since 3.0
	 */
	IBuildpathEntry[] readRawClasspath();

	/**
	 * Helper method for setting one option value only.
	 *<p>
	 * Equivalent to:
	 *
	 * <pre>
	 * 	Map options = this.getOptions(false);
	 * 	map.put(optionName, optionValue);
	 * 	this.setOptions(map)
	 * </pre>
	 * <p>
	 * For a complete description of the configurable options, see
	 * <code>PHPCore#getDefaultOptions</code>.
	 * </p>
	 *
	 * @param optionName the name of an option
	 * @param optionValue the value of the option to set. If <code>null</code>,
	 *            then the option is removed from project preferences.
	 * @throws NullPointerException if <code>optionName</code> is
	 *             <code>null</code> (see
	 *             {@link org.osgi.service.prefs.Preferences#put(String, String)}
	 *             ).
	 * @see PHPCore#getDefaultOptions()
	 * @since 3.0
	 */
	void setOption(String optionName, String optionValue);

	/**
	 * Sets the project custom options. All and only the options explicitly
	 * included in the given table are remembered; all previous option settings
	 * are forgotten, including ones not explicitly mentioned.
	 * <p>
	 * For a complete description of the configurable options, see
	 * <code>PHPCore#getDefaultOptions</code>.
	 * </p>
	 *
	 * @param newOptions the new options (key type: <code>String</code>; value
	 *            type: <code>String</code>), or <code>null</code> to flush all
	 *            custom options (clients will automatically get the global
	 *            PHPCore options).
	 * @see PHPCore#getDefaultOptions()
	 * @since 2.1
	 */
	void setOptions(Map newOptions);

	/**
	 * Sets the default output location of this project to the location
	 * described by the given workspace-relative absolute path.
	 * <p>
	 * The default output location is where class files are ordinarily generated
	 * (and resource files, copied). Each source classpath entries can also
	 * specify an output location for the generated class files (and copied
	 * resource files) corresponding to compilation units under that source
	 * folder. This makes it possible to arrange that generated class files for
	 * different source folders to end up in different output folders, and not
	 * necessarily the default output folder. This means that the generated
	 * class files for the project may end up scattered across several folders,
	 * rather than all in the default output folder (which is more standard).
	 * </p>
	 *
	 * @param path the workspace-relative absolute path of the default output
	 *            folder
	 * @param monitor the progress monitor
	 * @exception PHPModelException if the classpath could not be set. Reasons
	 *                include:
	 *                <ul>
	 *                <li>This PHP element does not exist
	 *                (ELEMENT_DOES_NOT_EXIST)</li>
	 *                <li>The path refers to a location not contained in this
	 *                project (<code>PATH_OUTSIDE_PROJECT</code>)
	 *                <li>The path is not an absolute path (
	 *                <code>RELATIVE_PATH</code>)
	 *                <li>The path is nested inside a package fragment root of
	 *                this project (<code>INVALID_PATH</code>)
	 *                <li>The output location is being modified during resource
	 *                change event notification (CORE_EXCEPTION)
	 *                </ul>
	 * @see #getOutputLocation()
	 * @see IBuildpathEntry#getOutputLocation()
	 */
	void setOutputLocation(IPath path, IProgressMonitor monitor) throws PHPModelException;

	/**
	 * Sets both the classpath of this project and its default output location
	 * at once. The classpath is defined using a list of classpath entries. In
	 * particular such a classpath may contain classpath variable entries.
	 * Classpath variable entries can be resolved individually (
	 * {@link PHPCore#getClasspathVariable(String)}), or the full classpath can
	 * be resolved at once using the helper method
	 * {@link #getResolvedClasspath(boolean)}.
	 * <p>
	 * A classpath variable provides an indirection level for better sharing a
	 * classpath. As an example, it allows a classpath to no longer refer
	 * directly to external JARs located in some user specific location. The
	 * classpath can simply refer to some variables defining the proper
	 * locations of these external JARs.
	 * </p>
	 * <p>
	 * If it is specified that this operation cannot modify resources, the
	 * .classpath file will not be written to disk and no error marker will be
	 * generated. To synchronize the .classpath with the in-memory classpath,
	 * one can use
	 * <code>setRawClasspath(readRawClasspath(), true, monitor)</code>.
	 * </p>
	 * <p>
	 * Setting the classpath to <code>null</code> specifies a default classpath
	 * (the project root). Setting the classpath to an empty array specifies an
	 * empty classpath.
	 * </p>
	 * <p>
	 * If a cycle is detected while setting this classpath (and if resources can
	 * be modified), an error marker will be added to the project closing the
	 * cycle. To avoid this problem, use
	 * {@link #hasClasspathCycle(IBuildpathEntry[])} before setting the
	 * classpath.
	 * <p>
	 * This operation acquires a lock on the workspace's root.
	 *
	 * @param entries a list of classpath entries
	 * @param outputLocation the default output location
	 * @param canModifyResources whether resources should be written to disk if
	 *            needed
	 * @param monitor the given progress monitor
	 * @exception PHPModelException if the classpath could not be set. Reasons
	 *                include:
	 *                <ul>
	 *                <li> This PHP element does not exist
	 *                (ELEMENT_DOES_NOT_EXIST)</li> <li> The classpath is being
	 *                modified during resource change event notification
	 *                (CORE_EXCEPTION) <li> The classpath failed the validation
	 *                check as defined by
	 *                {@link PHPConventions#validateClasspath(IPHPProject, IBuildpathEntry[], IPath)}
	 *                </ul>
	 * @see IBuildpathEntry
	 * @since 3.2
	 */
	void setRawClasspath(IBuildpathEntry[] entries, IPath outputLocation, boolean canModifyResources,
			IProgressMonitor monitor) throws PHPModelException;

	/**
	 * Sets the classpath of this project using a list of classpath entries. In
	 * particular such a classpath may contain classpath variable entries.
	 * Classpath variable entries can be resolved individually (
	 * {@link PHPCore#getClasspathVariable(String)}), or the full classpath can
	 * be resolved at once using the helper method
	 * {@link #getResolvedClasspath(boolean)}.
	 * <p>
	 * A classpath variable provides an indirection level for better sharing a
	 * classpath. As an example, it allows a classpath to no longer refer
	 * directly to external JARs located in some user specific location. The
	 * classpath can simply refer to some variables defining the proper
	 * locations of these external JARs.
	 * </p>
	 * <p>
	 * If it is specified that this operation cannot modify resources, the
	 * .classpath file will not be written to disk and no error marker will be
	 * generated. To synchronize the .classpath with the in-memory classpath,
	 * one can use
	 * <code>setRawClasspath(readRawClasspath(), true, monitor)</code>.
	 * </p>
	 * <p>
	 * Setting the classpath to <code>null</code> specifies a default classpath
	 * (the project root). Setting the classpath to an empty array specifies an
	 * empty classpath.
	 * </p>
	 * <p>
	 * If a cycle is detected while setting this classpath (and if resources can
	 * be modified), an error marker will be added to the project closing the
	 * cycle. To avoid this problem, use
	 * {@link #hasClasspathCycle(IBuildpathEntry[])} before setting the
	 * classpath.
	 * <p>
	 * This operation acquires a lock on the workspace's root.
	 *
	 * @param entries a list of classpath entries
	 * @param canModifyResources whether resources should be written to disk if
	 *            needed
	 * @param monitor the given progress monitor
	 * @exception PHPModelException if the classpath could not be set. Reasons
	 *                include:
	 *                <ul>
	 *                <li> This PHP element does not exist
	 *                (ELEMENT_DOES_NOT_EXIST)</li> <li> The classpath is being
	 *                modified during resource change event notification
	 *                (CORE_EXCEPTION) <li> The classpath failed the validation
	 *                check as defined by
	 *                {@link PHPConventions#validateClasspath(IPHPProject, IBuildpathEntry[], IPath)}
	 *                </ul>
	 * @see IBuildpathEntry
	 * @since 3.2
	 */
	void setRawClasspath(IBuildpathEntry[] entries, boolean canModifyResources, IProgressMonitor monitor)
			throws PHPModelException;

	/**
	 * Sets the classpath of this project using a list of classpath entries. In
	 * particular such a classpath may contain classpath variable entries.
	 * Classpath variable entries can be resolved individually (
	 * {@link PHPCore#getClasspathVariable(String)}), or the full classpath can
	 * be resolved at once using the helper method
	 * {@link #getResolvedClasspath(boolean)}.
	 * <p>
	 * A classpath variable provides an indirection level for better sharing a
	 * classpath. As an example, it allows a classpath to no longer refer
	 * directly to external JARs located in some user specific location. The
	 * classpath can simply refer to some variables defining the proper
	 * locations of these external JARs.
	 * <p>
	 * Setting the classpath to <code>null</code> specifies a default classpath
	 * (the project root). Setting the classpath to an empty array specifies an
	 * empty classpath.
	 * <p>
	 * If a cycle is detected while setting this classpath, an error marker will
	 * be added to the project closing the cycle. To avoid this problem, use
	 * {@link #hasClasspathCycle(IBuildpathEntry[])} before setting the
	 * classpath.
	 * <p>
	 * This operation acquires a lock on the workspace's root.
	 *
	 * @param entries a list of classpath entries
	 * @param monitor the given progress monitor
	 * @exception PHPModelException if the classpath could not be set. Reasons
	 *                include:
	 *                <ul>
	 *                <li> This PHP element does not exist
	 *                (ELEMENT_DOES_NOT_EXIST)</li> <li> The classpath is being
	 *                modified during resource change event notification
	 *                (CORE_EXCEPTION) <li> The classpath failed the validation
	 *                check as defined by
	 *                {@link PHPConventions#validateClasspath(IPHPProject, IBuildpathEntry[], IPath)}
	 *                </ul>
	 * @see IBuildpathEntry
	 */
	void setRawClasspath(IBuildpathEntry[] entries, IProgressMonitor monitor) throws PHPModelException;

	/**
	 * Sets the both the classpath of this project and its default output
	 * location at once. The classpath is defined using a list of classpath
	 * entries. In particular, such a classpath may contain classpath variable
	 * entries. Classpath variable entries can be resolved individually (see (
	 * {@link PHPCore#getClasspathVariable(String)}), or the full classpath can
	 * be resolved at once using the helper method
	 * {@link #getResolvedClasspath(boolean)}.
	 * <p>
	 * A classpath variable provides an indirection level for better sharing a
	 * classpath. As an example, it allows a classpath to no longer refer
	 * directly to external JARs located in some user specific location. The
	 * classpath can simply refer to some variables defining the proper
	 * locations of these external JARs.
	 * </p>
	 * <p>
	 * Setting the classpath to <code>null</code> specifies a default classpath
	 * (the project root). Setting the classpath to an empty array specifies an
	 * empty classpath.
	 * </p>
	 * <p>
	 * If a cycle is detected while setting this classpath, an error marker will
	 * be added to the project closing the cycle. To avoid this problem, use
	 * {@link #hasClasspathCycle(IBuildpathEntry[])} before setting the
	 * classpath.
	 * </p>
	 * <p>
	 * This operation acquires a lock on the workspace's root.
	 * </p>
	 *
	 * @param entries a list of classpath entries
	 * @param monitor the progress monitor
	 * @param outputLocation the default output location
	 * @exception PHPModelException if the classpath could not be set. Reasons
	 *                include:
	 *                <ul>
	 *                <li>This PHP element does not exist
	 *                (ELEMENT_DOES_NOT_EXIST)</li>
	 *                <li>Two or more entries specify source roots with the same
	 *                or overlapping paths (NAME_COLLISION)
	 *                <li>A entry of kind <code>CPE_PROJECT</code> refers to
	 *                this project (INVALID_PATH)
	 *                <li>This PHP element does not exist
	 *                (ELEMENT_DOES_NOT_EXIST)</li>
	 *                <li>The output location path refers to a location not
	 *                contained in this project (
	 *                <code>PATH_OUTSIDE_PROJECT</code>)
	 *                <li>The output location path is not an absolute path (
	 *                <code>RELATIVE_PATH</code>)
	 *                <li>The output location path is nested inside a package
	 *                fragment root of this project (<code>INVALID_PATH</code>)
	 *                <li>The classpath is being modified during resource change
	 *                event notification (CORE_EXCEPTION)
	 *                </ul>
	 * @see IBuildpathEntry
	 * @since 2.0
	 */
	void setRawClasspath(IBuildpathEntry[] entries, IPath outputLocation, IProgressMonitor monitor)
			throws PHPModelException;
}
